//
// Created by LoveHoneyYou on 2024-11-16.
//

#include "EventLoop.h"
#include "EpollDispatcher.h"
#include <csignal>
#include <cstring>
#include <sys/socket.h>
EventLoop::EventLoop()
            :EventLoop(std::string())
{}

EventLoop::EventLoop(const std::string &thread_name)
{
    is_quit_ = true;
    thread_id_ = std::this_thread::get_id();
    thread_name.empty() ? thread_name_ = "MainThread" : thread_name_ = thread_name;
    dispatcher_ = new EpollDispatcher(this);
    channel_map_.clear();
    int ret = socketpair(AF_UNIX,SOCK_STREAM,0,socket_pair_);
    if(ret == -1)
    {
        perror("socketpair");
        exit(0);
    }

    auto obj = std::bind(&EventLoop::Read_Message,this);
    Channel* channel = new Channel(socket_pair_[1],FD_Event::ReadEvent,obj, nullptr,nullptr,this);

    Add_Task(channel,ElemType::ADD);
}

EventLoop::~EventLoop()
{}

int EventLoop::Run()
{
    is_quit_ = false;
    if(thread_id_ != std::this_thread::get_id())
    {
        return -1;
    }

    while(!is_quit_)
    {
        dispatcher_->Dispatch();
        Process_Task_Queue();
    }
    return 0;
}

int EventLoop::Event_Active(int fd, int event)
{
    if(fd < 0)
    {
        return -1;
    }

    Channel* channel = channel_map_[fd];
    if((event & (int)FD_Event::ReadEvent) && channel->read_callback_)
    {
        channel->read_callback_((void*)(channel->Get_Arg()));
    }

    if((event & (int)FD_Event::WriteEvent) && channel->write_callback_)
    {
        channel->write_callback_((void*)(channel->Get_Arg()));
    }
    return 0;
}

int EventLoop::Add_Task(Channel *channel, const ElemType &type)
{
    mutex_.lock();
    ChannelElement* node = new ChannelElement;
    node->channel = channel;
    node->type_ = type;
    task_queue_.push(node);
    mutex_.unlock();

    if(thread_id_ == std::this_thread::get_id())
    {
        Process_Task_Queue();
    }
    else
    {
        Task_Wake_Up();
    }
    return 0;
}

int EventLoop::Process_Task_Queue()
{
    while(!task_queue_.empty())
    {
        mutex_.lock();
        ChannelElement* node = task_queue_.front();
        task_queue_.pop();
        mutex_.unlock();
        Channel* channel = node->channel;
        if(node->type_ == ElemType::ADD)
        {
            Add(channel);
        }
        else if(node->type_ == ElemType::DELETE)
        {
            Remove(channel);
        }
        else if(node->type_ == ElemType::MODIFY)
        {
            Modify(channel);
        }
        delete node;
    }
    return 0;
}

int EventLoop::Add(Channel *channel)
{
    int fd = channel->Get_Socket();
    if(channel_map_.find(fd) == channel_map_.end())
    {
        channel_map_.insert({fd,channel});
        dispatcher_->Set_Channel(channel);
        int ret = dispatcher_->Add();
        return ret;
    }
    return -1;
}

int EventLoop::Remove(Channel *channel)
{
    int fd = channel->Get_Socket();
    if(channel_map_.find(fd) == channel_map_.end())
    {
        return -1;
    }
    dispatcher_->Set_Channel(channel);
    int ret = dispatcher_->Remove();
    return ret;
}

int EventLoop::Modify(Channel *channel)
{
    int fd = channel->Get_Socket();
    if(channel_map_.find(fd) == channel_map_.end())
    {
        return -1;
    }
    dispatcher_->Set_Channel(channel);
    int ret = dispatcher_->Modify();
    return ret;
}

int EventLoop::Read_Local_Message(void *args)
{
    EventLoop* eventloop = (EventLoop*)args;
    char buf[256]{};
    read(eventloop->socket_pair_[1],buf,sizeof(buf));
    return 0;
}

void EventLoop::Task_Wake_Up()
{
    const char* msg = "I just like you!";
    write(socket_pair_[0],msg,strlen(msg));
}

int EventLoop::Free_Channel(Channel *channel)
{
    auto it = channel_map_.find(channel->Get_Socket());
    if(it != channel_map_.end())
    {
        channel_map_.erase(it);
        close(channel->Get_Socket());
        delete channel;
    }
    return 0;
}

int EventLoop::Read_Message()
{
    char buf[256]{};
    read(socket_pair_[1],buf,sizeof(buf));
    return 0;
}
